﻿using System;
using System.Collections;
using System.Linq;
using System.Text;
using System.IO;

namespace P2
{
    class Program
    {
        static ArrayList fluxoDeTokens = new ArrayList();
        static Hashtable ts = new Hashtable();
        static ArrayList numbers = new ArrayList();
        static ArrayList variables = new ArrayList();
        static int i = 0; //percorredor de fluxo de tokens        

        static void Main(string[] args)
        {                        
            FileStream file = new FileStream("c:\\path.txt", FileMode.Open, FileAccess.Read);
            StreamReader sr = new StreamReader(file);
            // Read contents of file into a string
            string s = sr.ReadToEnd();
            Console.Write(s);            
            // Close StreamReader
            sr.Close();
            // Close file
            file.Close();
            lex lexico = new lex();

           fluxoDeTokens = lexico.AnalisaEntrada(s);
           ts = lexico.GetTabSimb();

           //Console.ReadLine();
           Console.Write("\n\n");
           
           int state = 12;
           while (i < fluxoDeTokens.Count)
           {
               Tk token = (Tk)fluxoDeTokens[i];
               switch (state)
               {
                   case 12:
                       if ("pr".Equals(token.getTipo()) && "program".Equals(token.getValor()))
                       {
                           state = 15;
                       }
                       else
                       {
                           state = 100;
                       }
                       i++;
                       break;

                   case 15:
                       if ("pr".Equals(token.getTipo()) && "fun".Equals(token.getValor()))
                       {
                           state = 0;
                       }
                       else if ("pr".Equals(token.getTipo()) && "declare".Equals(token.getValor()))
                       {
                           state = 19;
                       }
                       else
                       {
                           state = 100;
                       }
                       i++;
                       break;

                   case 0:
                       if (automatoTipo())
                       {
                           state = 1;
                       }
                       else
                       {
                           state = 100;
                       }
                       i++;
                       break;

                   case 1:
                       if (automatoID())
                       {
                           state = 2;
                       }
                       else
                       {
                           state = 100;
                       }
                       i++;
                       break;

                   case 2:
                       if ("delim".Equals(token.getTipo()) && "(".Equals(token.getValor()))
                       {
                           state = 3;
                       }
                       else
                       {
                           state = 100;
                       }
                       i++;
                       break;

                   case 3:
                       if (automatoTipo())
                       {
                           state = 4;
                       }
                       else
                       {
                           state = 100;
                       }
                       i++;
                       break;

                   case 4:
                       if (automatoID())
                       {
                           state = 5;
                       }
                       else
                       {
                           state = 100;
                       }
                       i++;
                       break;

                   case 5:
                       if ("outro".Equals(token.getTipo()) && "'".Equals(token.getValor()))
                       {
                           state = 3;
                       }
                       else if ("delim".Equals(token.getTipo()) && ")".Equals(token.getValor()))
                       {
                           state = 6;
                       }
                       else
                       {
                           state = 100;
                       }
                       i++;
                       break;

                   case 6:
                       if ("pr".Equals(token.getTipo()) && "declare".Equals(token.getValor()))
                       {
                           state = 7;
                       }
                       else
                       {
                           state = 100;
                       }
                       i++;
                       break;

                   case 7:
                       if (automatoTipo())
                       {
                           state = 8;
                       }
                       else
                       {
                           state = 100;
                       }
                       i++;
                       break;

                   case 8:
                       if (automatoID())
                       {
                           state = 9;
                       }
                       else
                       {
                           state = 100;
                       }
                       i++;
                       break;

                   case 9:
                       if ("outro".Equals(token.getTipo()) && ";".Equals(token.getValor()))
                       {
                           state = 7;
                       }
                       else if ("pr".Equals(token.getTipo()) && "begin".Equals(token.getValor()))
                       {
                           state = 10;
                       }
                       else
                       {
                           state = 100;
                       }
                       i++;
                       break;

                   case 10:
                       if (automatoSeqComandos())
                       {
                           state = 11;
                       }
                       else
                       {
                           state = 100;
                       }
                       i++;
                       break;

                   case 11:
                       if ("pr".Equals(token.getTipo()) && "return".Equals(token.getValor()))
                       {
                           state = 13;
                       }
                       else
                       {
                           state = 100;
                       }
                       i++;
                       break;

                   case 13:
                       if (automatoID() || automatoNumero())
                       {
                           state = 14;
                       }
                       else
                       {
                           state = 100;
                       }
                       i++;
                       break;

                   case 14:
                       if ("pr".Equals(token.getTipo()) && "funend".Equals(token.getValor()))
                       {
                           state = 15;
                       }
                       else
                       {
                           state = 100;
                       }
                       i++;
                       break;                   

                   case 17:
                       if (automatoID())
                       {
                           state = 18;
                           variables.Add(token.getValor());
                       }
                       else
                       {
                           state = 100;
                       }
                       i++;
                       break;

                   case 18:
                       if ("outro".Equals(token.getTipo()) && ";".Equals(token.getValor()))
                       {
                           state = 19;
                       }
                       else
                       {
                           state = 100;
                       }
                       i++;
                       break;

                   case 19:
                       if (automatoTipo())
                       {
                           state = 17;
                       }
                       else if ("pr".Equals(token.getTipo()) && "begin".Equals(token.getValor()))
                       {
                           state = 20;                           
                       }
                       else
                       {
                           state = 100;
                       }
                       i++;
                       break;

                   case 20:
                       if (automatoSeqComandos())
                       {
                           state = 21;
                       }
                       else
                       {
                           state = 100;
                       }
                       i++;
                       break;

                   case 21:
                       if ("pr".Equals(token.getTipo()) && "programend".Equals(token.getValor()))
                       {
                           state = 16;
                       }
                       else
                       {
                           state = 100;
                       }
                       i++;
                       break;

                   case 16:
                       if ("outro".Equals(token.getTipo()) && ";".Equals(token.getValor()))
                       {
                           state = 200;
                       }
                       else
                       {
                           state = 100;
                       }
                       break; 

                   case 200:
                       Console.Write("ACEITO!!!\n\n");                                            
                       i++;
                       break;

                   case 100:
                       Console.Write("ERRO DE SINTAXE!!!\n");                       
                       return;
                       break;
               }
           }
           if (("pr".Equals(((Tk)fluxoDeTokens[i - 2]).getTipo()) && 
               "programend".Equals(((Tk)fluxoDeTokens[i - 2]).getValor())) &&
               ("outro".Equals(((Tk)fluxoDeTokens[i - 1]).getTipo()) &&
               ";".Equals(((Tk)fluxoDeTokens[i - 1]).getValor())))
           {
               Console.Write("FIM DE PROGRAMA\n");
               imprimeSaida();
           }
           else
           {
               Console.Write("ERRO DE SINTAXE!!!\n");               
           }
           Console.ReadLine();
        }

        static bool automatoSeqComandos()
        {
            int i_entrada = i;            
            int state = 45;
            while (i < fluxoDeTokens.Count)
            {
                Tk token = (Tk)fluxoDeTokens[i];
                Tk token_aux = null;
                int i_atual = 0;
                switch (state)
                {
                    case 45:
                        if ("pr".Equals(token.getTipo()) && "while".Equals(token.getValor()))
                        {
                            state = 9;
                            i++;
                        }
                        else if ("pr".Equals(token.getTipo()) && "call".Equals(token.getValor()))
                        {
                            state = 31;
                            i++;
                        }
                        else if ("pr".Equals(token.getTipo()) && "switch".Equals(token.getValor()))
                        {
                            state = 14;
                            i++;
                        }
                        else if ("pr".Equals(token.getTipo()) && "if".Equals(token.getValor()))
                        {
                            state = 1;
                            i++;
                        }
                        else if ("pr".Equals(token.getTipo()) && "scan".Equals(token.getValor()))
                        {
                            state = 42;
                            i++;
                        }
                        else if ("pr".Equals(token.getTipo()) && "print".Equals(token.getValor()))
                        {
                            state = 35;
                            i++;
                        }
                        else if ("pr".Equals(token.getTipo()) && "for".Equals(token.getValor()))
                        {
                            state = 20;
                            i++;
                        }
                        else if ("pr".Equals(token.getTipo()) && ("programend".Equals(token.getValor()) || 
                                                                  "ifend".Equals(token.getValor()) || 
                                                                  "whilend".Equals(token.getValor()) || 
                                                                  "forend".Equals(token.getValor()) || 
                                                                  "break".Equals(token.getValor()) || 
                                                                  "else".Equals(token.getValor()) || 
                                                                  "switchend".Equals(token.getValor())))
                        {
                            state = 200;
                        }
                        else if (automatoID())
                        {
                            state = 32;
                            i++;
                        }
                        else
                        {
                            state = 200;
                        }                        
                        break;

                    case 9:
                        i_atual = i;

                        if (automatoBoolean())
                        {
                            token_aux = (Tk)fluxoDeTokens[i + 1];

                            if ("outro".Equals(token_aux.getTipo()) && ";".Equals(token_aux.getValor()))
                            {
                                state = 11;
                            }
                            else
                            {
                                i = i_atual;
                                if (automatoExpressao())
                                {
                                    state = 8;
                                }
                                else
                                {
                                    state = 100;
                                }
                            }                            
                        }
                        else if (automatoExpressao())
                        {
                            state = 8;
                        }                        
                        else
                        {
                            state = 100;
                        }
                        i++;
                        break;

                    case 8:
                        if (automatoComparador())
                        {
                            state = 10;
                        }
                        else
                        {
                            state = 100;
                        }
                        i++;
                        break;

                    case 10:
                        if (automatoExpressao())
                        {
                            state = 11;
                        }
                        else
                        {
                            state = 100;
                        }
                        i++;
                        break;

                    case 11:
                        if ("pr".Equals(token.getTipo()) && "do".Equals(token.getValor()))
                        {
                            state = 12;                            
                        }
                        else
                        {
                            state = 100;
                        }
                        i++;
                        break;

                    case 12:
                        if (automatoSeqComandos())
                        {
                            state = 13;
                        }
                        else
                        {
                            state = 100;
                        }
                        i++;
                        break;

                    case 13:
                        if ("pr".Equals(token.getTipo()) && "whilend".Equals(token.getValor()))
                        {
                            state = 44;
                        }
                        else
                        {
                            state = 100;
                        }
                        i++;
                        break;

                    case 44:
                        if ("outro".Equals(token.getTipo()) && ";".Equals(token.getValor()))
                        {
                            state = 45;
                        }
                        else
                        {
                            state = 100;
                        }
                        i++;
                        break;

                    case 31:
                        if (automatoID())
                        {
                            state = 38;
                        }
                        else
                        {
                            state = 100;
                        }
                        i++;
                        break;

                    case 38:
                        if ("delim".Equals(token.getTipo()) && "(".Equals(token.getValor()))
                        {
                            state = 41;
                        }
                        else
                        {
                            state = 100;
                        }
                        i++;
                        break;

                    case 41:
                        if ("delim".Equals(token.getTipo()) && ")".Equals(token.getValor()))
                        {
                            state = 44;
                        }
                        else if (automatoID())
                        {
                            state = 40;
                        }
                        else
                        {
                            state = 100;
                        }
                        i++;
                        break;

                    case 40:
                        if ("delim".Equals(token.getTipo()) && ")".Equals(token.getValor()))
                        {
                            state = 44;
                        }
                        else if ("outro".Equals(token.getTipo()) && ",".Equals(token.getValor()))
                        {
                            state = 39;
                        }
                        else
                        {
                            state = 100;
                        }
                        i++;
                        break;

                    case 39:
                        if (automatoID())
                        {
                            state = 40;
                        }
                        else
                        {
                            state = 100;
                        }
                        i++;
                        break;

                    case 14:
                        if (automatoID())
                        {
                            state = 15;
                        }
                        else
                        {
                            state = 100;
                        }
                        i++;
                        break;

                    case 15:
                        if ("pr".Equals(token.getTipo()) && "case".Equals(token.getValor()))
                        {
                            state = 16;
                        }                        
                        else
                        {
                            state = 100;
                        }
                        i++;
                        break;

                    case 16:
                        if (automatoID())
                        {
                            state = 17;
                        }
                        else
                        {
                            state = 100;
                        }
                        i++;
                        break;

                    case 17:
                        if (automatoSeqComandos())
                        {
                            state = 18;
                        }
                        else
                        {
                            state = 100;
                        }
                        i++;
                        break;

                    case 18:
                        if ("pr".Equals(token.getTipo()) && "break".Equals(token.getValor()))
                        {
                            state = 37;
                        }
                        else
                        {
                            state = 100;
                        }
                        i++;
                        break;

                    case 37:
                        if ("pr".Equals(token.getTipo()) && "switchend".Equals(token.getValor()))
                        {
                            state = 44;
                        }
                        else if ("pr".Equals(token.getTipo()) && "case".Equals(token.getValor()))
                        {
                            state = 16;
                        }
                        else
                        {
                            state = 100;
                        }
                        i++;
                        break;

                    case 1:
                        if (automatoExpressao())
                        {
                            state = 0;
                        }
                        else
                        {
                            state = 100;
                        }
                        i++;
                        break;

                    case 0:
                        if (automatoComparador())
                        {
                            state = 2;
                        }
                        else
                        {
                            state = 100;
                        }
                        i++;
                        break;

                    case 2:
                        if (automatoExpressao())
                        {
                            state = 3;
                        }
                        else
                        {
                            state = 100;
                        }
                        i++;
                        break;

                    case 3:
                        if ("pr".Equals(token.getTipo()) && "then".Equals(token.getValor()))
                        {
                            state = 5;
                        }
                        else
                        {
                            state = 100;
                        }
                        i++;
                        break;

                    case 5:
                        if (automatoSeqComandos())
                        {
                            state = 7;
                        }
                        else
                        {
                            state = 100;
                        }
                        i++;
                        break;

                    case 7:
                        if ("pr".Equals(token.getTipo()) && "else".Equals(token.getValor()))
                        {
                            state = 4;
                        }
                        else if ("pr".Equals(token.getTipo()) && "ifend".Equals(token.getValor()))
                        {
                            state = 44;
                        }
                        else
                        {
                            state = 100;
                        }
                        i++;
                        break;

                    case 4:
                        if (automatoExpressao())
                        {
                            state = 6;
                        }
                        else
                        {
                            state = 100;
                        }
                        i++;
                        break;

                    case 6:
                        if ("pr".Equals(token.getTipo()) && "ifend".Equals(token.getValor()))
                        {
                            state = 44;
                        }
                        else
                        {
                            state = 100;
                        }
                        i++;
                        break;

                    case 32:
                        if ("atrib".Equals(token.getTipo()) && "=".Equals(token.getValor()))
                        {
                            state = 34;
                        }
                        else
                        {
                            state = 100;
                        }
                        i++;
                        break;

                    case 34:
                        if ("pr".Equals(token.getTipo()) && "call".Equals(token.getValor()))
                        {
                            state = 31;
                        }
                        else if (automatoExpressao())
                        {
                            state = 44;
                        }
                        else
                        {
                            state = 100;
                        }
                        i++;
                        break;

                    case 42:
                        if (automatoID())
                        {
                            state = 44;
                        }
                        else
                        {
                            state = 100;
                        }
                        i++;
                        break;

                    case 35:
                        if ("outro".Equals(token.getTipo()) && "\"".Equals(token.getValor()))
                        {
                            state = 33;
                        }
                        else if (automatoExpressao())
                        {
                            state = 44;
                        }
                        else
                        {
                            state = 100;
                        }
                        i++;
                        break;

                    case 33:
                        if (automatoExpressao())
                        {
                            state = 43;
                        }
                        else
                        {
                            state = 100;
                        }
                        i++;
                        break;

                    case 43:
                        if ("outro".Equals(token.getTipo()) && "\"".Equals(token.getValor()))
                        {
                            state = 44;
                        }                       
                        else
                        {
                            state = 100;
                        }
                        i++;
                        break;

                    case 20:
                        if ("delim".Equals(token.getTipo()) && "(".Equals(token.getValor()))
                        {
                            state = 21;
                        }
                        else
                        {
                            state = 100;
                        }
                        i++;
                        break;

                    case 21:
                        if (automatoID())
                        {
                            state = 22;
                        }
                        else
                        {
                            state = 100;
                        }
                        i++;
                        break;

                    case 22:
                        if ("atrib".Equals(token.getTipo()) && "=".Equals(token.getValor()))
                        {
                            state = 23;
                        }
                        else
                        {
                            state = 100;
                        }
                        i++;
                        break;

                    case 23:
                        if (automatoExpressao())
                        {
                            state = 24;
                        }
                        else
                        {
                            state = 100;
                        }
                        i++;
                        break;

                    case 24:
                        if ("outro".Equals(token.getTipo()) && ";".Equals(token.getValor()))
                        {
                            state = 25;
                        }
                        else
                        {
                            state = 100;
                        }
                        i++;
                        break;

                    case 25:
                        i_atual = i;

                        if (automatoBoolean())
                        {
                            token_aux = (Tk)fluxoDeTokens[i + 1];

                            if ("outro".Equals(token_aux.getTipo()) && ";".Equals(token_aux.getValor()))
                            {
                                state = 27;
                            }
                            else
                            {
                                i = i_atual;
                                if (automatoExpressao())
                                {
                                    state = 19;
                                }
                                else
                                {
                                    state = 100;
                                }
                            }
                        }
                        else if (automatoExpressao())
                        {
                            state = 19;
                        }
                        else
                        {
                            state = 100;
                        }
                        i++;
                        break;

                    case 19:
                        if (automatoComparador())
                        {
                            state = 26;
                        }
                        else
                        {
                            state = 100;
                        }
                        i++;
                        break;

                    case 26:
                        if (automatoExpressao())
                        {
                            state = 27;
                        }
                        else
                        {
                            state = 100;
                        }
                        i++;
                        break;

                    case 27:
                        if ("outro".Equals(token.getTipo()) && ";".Equals(token.getValor()))
                        {
                            state = 28;
                        }
                        else
                        {
                            state = 100;
                        }
                        i++;
                        break;

                    case 28:
                        if (automatoID())
                        {
                            state = 46;
                        }
                        else
                        {
                            state = 100;
                        }
                        i++;
                        break;

                    case 46:
                        if ("atrib".Equals(token.getTipo()) && "=".Equals(token.getValor()))
                        {
                            state = 47;
                        }
                        else
                        {
                            state = 100;
                        }
                        i++;
                        break;

                    case 47:
                        if (automatoExpressao())
                        {
                            state = 29;
                        }
                        else
                        {
                            state = 100;
                        }
                        i++;
                        break;

                    case 29:
                        if ("delim".Equals(token.getTipo()) && ")".Equals(token.getValor()))
                        {
                            state = 30;
                        }
                        else
                        {
                            state = 100;
                        }
                        i++;
                        break;

                    case 30:
                        if (automatoSeqComandos())
                        {
                            state = 36;
                        }
                        else
                        {
                            state = 100;
                        }
                        i++;
                        break;

                    case 36:
                        if ("pr".Equals(token.getTipo()) && "forend".Equals(token.getValor()))
                        {
                            state = 44;
                        }
                        else
                        {
                            state = 100;
                        }
                        i++;
                        break;

                    case 100:
                        i = i_entrada;
                        return false;
                        break;

                    case 200:
                        i--;
                        return true;
                        break;
                }
            }
            i = i_entrada;
            return false;
        }

        static bool automatoBoolean()
        {
            int i_entrada = i;
            int state = 4;            
            while (i < fluxoDeTokens.Count)
            {
                Tk token = (Tk)fluxoDeTokens[i];
                switch (state)
                {
                    case 4:
                        if ("pr".Equals(token.getTipo()) && "not".Equals(token.getValor()))
                        {
                            state = 3;
                        }
                        else if ("delim".Equals(token.getTipo()) && "(".Equals(token.getValor()))
                        {
                            state = 0;
                        }
                        else if (automatoID())
                        {
                            state = 5;
                        }
                        else
                        {
                            state = 100;
                        }
                        i++;
                        break;

                    case 3:
                        if (automatoID())
                        {
                            state = 5;
                        }
                        else
                        {
                            state = 100;
                        }
                        i++;
                        break;

                    case 5:
                        if ("pr".Equals(token.getTipo()) && ("and".Equals(token.getValor()) || 
                                                             "or".Equals(token.getValor())))
                        {
                            state = 2;
                            i++;
                        }
                        else
                        {
                            state = 200;
                        }                        
                        break;

                    case 2:
                        if ("pr".Equals(token.getTipo()) && "not".Equals(token.getValor()))
                        {
                            state = 3;
                        }
                        else if ("delim".Equals(token.getTipo()) && "(".Equals(token.getValor()))
                        {
                            state = 0;
                        }                        
                        else
                        {
                            state = 100;
                        }
                        i++;
                        break;

                    case 0:
                        if (automatoBoolean())
                        {
                            state = 1;
                        }
                        else
                        {
                            state = 100;
                        }
                        i++;
                        break;

                    case 1:
                        if ("delim".Equals(token.getTipo()) && ")".Equals(token.getValor()))
                        {
                            state = 5;
                        }
                        else
                        {
                            state = 100;
                        }
                        i++;
                        break;

                    case 100:
                        i = i_entrada;
                        return false;
                        break;

                    case 200:
                        i--;
                        return true;
                        break;
                }
            }
            i = i_entrada;
            return false;
        }

        static bool automatoExpressao()
        {
            int i_entrada = i;
            int state = 2;
            while (i < fluxoDeTokens.Count)
            {
                Tk token = (Tk)fluxoDeTokens[i];
                switch (state)
                {
                    case 2:
                        if ("delim".Equals(token.getTipo()) && "(".Equals(token.getValor()))
                        {
                            state = 0;
                        }
                        else if (automatoID() || automatoNumero())
                        {
                            state = 3;
                        }
                        else
                        {
                            state = 100;
                        }
                        i++;
                        break;

                    case 0:
                        if (automatoExpressao())
                        {
                            state = 1;
                        }
                        else
                        {
                            state = 100;
                        }
                        i++;
                        break;

                    case 1:
                        if ("delim".Equals(token.getTipo()) && ")".Equals(token.getValor()))
                        {
                            state = 3;
                        }                        
                        else
                        {
                            state = 100;
                        }
                        i++;
                        break;

                    case 3:
                        if ("op".Equals(token.getTipo()) && ("*".Equals(token.getValor()) ||
                                                             "+".Equals(token.getValor()) ||
                                                             "/".Equals(token.getValor()) ||
                                                             "-".Equals(token.getValor())))
                        {
                            state = 2;
                            i++;
                        }
                        else
                        {
                            state = 200;
                        }                        
                        break;

                    case 100:
                        i = i_entrada;
                        return false;
                        break;

                    case 200:
                        i--;
                        return true;
                        break;
                }
            }
            i = i_entrada;
            return false;
        }

        static bool automatoTipo()
        {
            Tk token = (Tk)fluxoDeTokens[i];
            if ("pr".Equals(token.getTipo()) && ("bool".Equals(token.getValor()) || 
                                                 "char".Equals(token.getValor()) || 
                                                 "int".Equals(token.getValor())))
            {
                return true;
            }
            else
            {
                return false;
            }
        }

        static bool automatoID()
        {
            Tk token = (Tk)fluxoDeTokens[i];
            if ("id".Equals(token.getTipo()))
            {
                return true;
            }
            else
            {
                return false;
            }
        }

        static bool automatoNumero()
        {
            Tk token = (Tk)fluxoDeTokens[i];
            if ("num".Equals(token.getTipo()))
            {
                bool jaExiste = false;
                int j = 0;
                for (j = 0; j < numbers.Count; j++)
                {
                    if (numbers[j] == token.getValor())
                    {
                        jaExiste = true;
                    }
                }
                if(!jaExiste){
                    numbers.Add(token.getValor());
                }                
                return true;
            }
            else
            {
                return false;
            }
        }

        static bool automatoComparador()
        {
            Tk token = (Tk)fluxoDeTokens[i];
            if ("comp".Equals(token.getTipo()) && ("==".Equals(token.getValor()) ||
                                                   "<>".Equals(token.getValor()) ||
                                                   "<".Equals(token.getValor()) ||
                                                   ">".Equals(token.getValor()) ||
                                                   "<=".Equals(token.getValor()) ||
                                                   ">=".Equals(token.getValor())))
            {
                return true;
            }
            else
            {
                return false;
            }
        }

        static void imprimeSaida()
        {
            StreamWriter srw = new StreamWriter("c:\\saida.asm");

            srw.Write("@ =0\n");
            srw.Write("JP INICIO\n");
            int j = 0;
            for(j = 0; j < numbers.Count; j++){
                srw.Write("NUM_" + numbers[j] + " K =" + numbers[j] + "\n");
            }
            for (j = 0; j < variables.Count; j++)
            {
                srw.Write(variables[j] + " K =0\n");
            }
            srw.Write("@ =1000\n");

            srw.Write("HM =0");
            srw.Close();
        }
    }
}